package org.jprobe;

import java.io.File;
import java.io.IOException;
import java.util.Arrays;
import java.util.LinkedList;
import java.util.List;
import java.util.Set;

import org.jprobe.classpath.ClassPathReader;
import org.jprobe.utils.AntBuilder;
import org.jprobe.utils.IOUtils;
import org.jprobe.utils.XmlUtils;
import org.w3c.dom.Document;
import org.w3c.dom.NodeList;
/**
 * Project explorer implementation
 *
 * @author Hussain Al-Mutawa
 * @version 1.0
 * @since 1.0
 */
public class ProjectExplorer implements ProjectExplorerInterface<CoverageResults, JUnitResults> {
	/** //TODO add documentation **/
	private transient int progress=0;
	/** //TODO add documentation **/
	private transient String project;
	/** //TODO add documentation **/
	private transient List<String>	files,sourceDirectories;
	/** //TODO add documentation **/
	private transient CoverageResults coverageResults;
	/** //TODO add documentation **/
	private transient JUnitResults junitResults;
	/** //TODO add documentation **/
	private transient Set<String>packages;
	/** //TODO add documentation **/
	private ProjectExplorer(){super();}
	/**
	 * initializes the project explorer
	 * @param project the full path to the project
	 * @throws JProbeRuntimeException if the project is not a java and eclipse generated project
	 */
	public ProjectExplorer(final String project){
		this();
		this.setProject(project);
	}

	@Override
	public String[] getFiles() {
		return files.toArray(new String[files.size()]);
	}

	@Override
	public String[] getSourceDirectories() throws JProbeException{
		if(sourceDirectories==null){
			final Document doc = XmlUtils.getDocument(project+"/.classpath");
			final NodeList nodeList = XmlUtils.xpath(doc, "//classpathentry[@kind='src']");
			sourceDirectories=new LinkedList<String>();
			for(int i=0;i<nodeList.getLength();i++){
				sourceDirectories.add( nodeList.item(i).getAttributes().getNamedItem("path").getNodeValue() );
			}
		}
		return sourceDirectories.toArray(new String[sourceDirectories.size()]);
	}

	@Override
	public void addLibraryFolder() throws IOException{
		new File(project+"/lib").mkdirs();
	}

	public void copyLibraries() throws IOException{
		final String lib = project+"/lib";
		copyLibrary(lib,"emma.jar");
		copyLibrary(lib,"emma_ant.jar");
		copyLibrary(lib,"junit-4.8.2.jar");
		copyLibrary(lib,"junit-noframes.xsl");
	}
	/**
	 *
	 * @param libDir
	 * @param library
	 * @throws IOException
	 */
	public void copyLibrary(final String libDir,final String library) throws IOException{
		IOUtils.copy("./lib/"+library, libDir+"/"+library);
	}

	@Override
	public void copyTestingLibraries() {
		throw new UnsupportedOperationException("Not Implemented yet");
	}

	@Override
	public void createTestingANTScript() {
		throw new UnsupportedOperationException("Not Implemented yet");
	}

	@Override
	public boolean runTests() {
		return false;
	}

	@Override
	public CoverageResults getCoverageResult() {
		return coverageResults;
	}

	@Override
	public JUnitResults getJUnitResults() {
		return junitResults;
	}

	@Override
	public String getProject() {
		return project;
	}

	@Override
	public void createUnitTestCases() throws IOException, JProbeException{
		if(new File(project+"/jprobe").mkdirs()){
			//compile source directories
			final int iSources=this.getSourceDirectories().length;
			for(int i=0;i<iSources;i++){
				compile(this.getSourceDirectories()[i]);
				progress+=(33*(i/iSources));
			}
			progress=33;
			//get the project packages/classes
			//final LinkedList<String>pckgs=new LinkedList<String>();

			for(int i=0;i<iSources;i++){

				progress+=(33*(i/iSources));
			}
			progress=66;
			//generate a unit case for each class
			progress=100;
		}

	}

	@Override
	public void compile() throws IOException{
		try {
			compile(getSourceDirectories()[0]);
		} catch (final JProbeException e1) {
			e1.printStackTrace();
			throw new IOException(e1);
		}
	}

	@Override
	public void compile(final String sourceDirectory) throws IOException{
		final String compileFile = project+"/compile.xml";
		IOUtils.writeToFile(compileFile, getBuild(sourceDirectory));
		new AntBuilder(new File(compileFile));
	}
	/**
	 * gets the build directory for a given project usnig the source directory
	 * @param sourceDirectory the source directory of the code
	 * @return the path of the build directory
	 * @throws IOException if the path does not exist
	 */
	protected String getBuild(final String sourceDirectory) throws IOException{
		return IOUtils.readFromFileSys("./compile.xml")
			.replace("PROJECT_NAME", project)
			.replace("SOURCE", sourceDirectory);
	}

	@Override
	public int getProgress() {
		return progress;
	}

	@Override
	public String[] getPackages() throws JProbeException{
		if(packages==null){
			packages=ClassPathReader.instance.getClassPath().getPackages();
		}
		return packages.toArray(new String[packages.size()]);
	}

	@Override
	public final void setProject(final String currentProject) {
		this.project=currentProject;
		if(project==null || "".equals(project)){
			throw new JProbeRuntimeException("Project folder is null or empty");
		}

		final File dir = new File(project);
		if(!dir.exists()){
			throw new JProbeRuntimeException("Project folder does not exist");
		}
		this.files=Arrays.asList(dir.list());

		if(!Workspace.isEclipseJavaProject(project)){
			throw new JProbeRuntimeException("Not a Java project");
		}

		this.coverageResults=new CoverageResults(project);
		this.junitResults=new JUnitResults(project);
	}


}
